package com.elhakimz.matra.scene;

import com.elhakimz.matra.util.GlobalVars;
import com.elhakimz.matra.util.SceneUtil;
import com.elhakimz.matra.MatraSystem;
import com.jme.light.DirectionalLight;
import com.jme.light.PointLight;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Camera;
import com.jme.renderer.pass.RenderPass;
import com.jme.renderer.pass.BasicPassManager;
import com.jme.math.Vector3f;
import com.jme.math.Plane;
import com.jme.scene.shape.Box;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.Skybox;
import com.jme.scene.state.FogState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.ZBufferState;
import com.jme.scene.state.LightState;
import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.util.TextureManager;
import com.jmex.effects.water.WaterRenderPass;

import java.nio.FloatBuffer;

/**
 * Created by IntelliJ IDEA.
 * User: abiel
 * Date: Feb 18, 2010
 * Time: 10:57:17 PM
 * To change this template use File | Settings | File Templates.
 */
public class SceneManager {

    private WaterRenderPass waterEffectRenderPass;
    private Box waterQuad;
    private Spatial splatTerrain;
    private Spatial reflectionTerrain;

    private Skybox skybox;
    private Camera cam;
    private BasicPassManager pManager;
    private LightState lightState;

    private float farPlane = 10000.0f;
    private float textureScale = 0.07f;
    private float globalSplatScale = 90.0f;

    private Node rootNode;



    public SceneManager(Node rootNode, Camera cam,  LightState lightState) {
        this.rootNode=rootNode;
        this.cam = cam;
        this.pManager = pManager;
        this.lightState = lightState;
        setupCamera();
        lightState.setEnabled(false);
        //setupEnvironment();
        //setupLights();
        //buildSkyBox();
        //rootNode.attachChild(skybox);
        //setupWater();
        setupScene();
        //setupObjects();
        rootNode.attachChild(GlobalVars.sceneNode);
        rootNode.attachChild(GlobalVars.pickNode);

    }

     private void setupLights(){
        lightState.detachAll();
        rootNode.setLightCombineMode(Spatial.LightCombineMode.Inherit);

      DirectionalLight dr = new DirectionalLight();
        dr.setEnabled(true);
        dr.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        dr.setAmbient(new ColorRGBA(.6f, .6f, .5f, .5f));
        dr.setDirection(new Vector3f(0.5f, -0.8f, 0.5f).normalizeLocal());
        dr.setShadowCaster(true);

       // Another light so there is no full darkness.
        PointLight pl = new PointLight();
        pl.setEnabled(true);
        pl.setDiffuse(new ColorRGBA(.2f, .2f, .23f, 1.0f));
        pl.setAmbient(new ColorRGBA(.25f, .25f, .28f, .25f));
        pl.setLocation(new Vector3f(20, 20, 20));


		lightState.detachAll();
		lightState.attach(dr);
		lightState.attach(pl);
		lightState.setGlobalAmbient(new ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f));
   }


    private void setupScene(){
        Node plane = SceneUtil.CreateOcean();
        GlobalVars.sceneNode.attachChild(plane);

        Node grid = SceneUtil.CreateGrid(500, 500, 100); //grid is 500x500 km divided per 10km
        GlobalVars.sceneNode.attachChild(grid);
    }

       private void setupCamera(){
        cam.setFrustumPerspective(45.0f, (float) MatraSystem.disp.getWidth()
                / (float) MatraSystem.disp.getHeight(), 1f, farPlane);
        cam.setLocation(new Vector3f(-320, 80, -270));
        cam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
        cam.update();

        CullState cs = MatraSystem.disp.getRenderer().createCullState();
        cs.setCullFace(CullState.Face.Back);
        rootNode.setRenderState(cs);
       }



        private void setupEnvironment(){

        FogState fogState = MatraSystem.disp.getRenderer().createFogState();
        fogState.setDensity(1.0f);
        fogState.setEnabled(true);
        fogState.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        fogState.setEnd(farPlane);
        fogState.setStart(farPlane / 10.0f);
        fogState.setDensityFunction(FogState.DensityFunction.Linear);
        fogState.setQuality(FogState.Quality.PerVertex);
        rootNode.setRenderState(fogState);
    }


    private void setupWater(){
        waterEffectRenderPass = new WaterRenderPass(cam, 6, false, true);
                waterEffectRenderPass.setWaterPlane(new Plane(new Vector3f(0f, 1.0f,
                        0f), 0.0f));
                waterEffectRenderPass.setClipBias(1.0f);
                waterEffectRenderPass.setReflectionThrottle(0.0f);
                waterEffectRenderPass.setRefractionThrottle(0.0f);

               // waterQuad = new Quad("waterQuad", 500, 500);
                waterQuad = new Box("waterQuad",new Vector3f(-500, 0.0f, -500),
                          new Vector3f(500, 0.0f, 500));
                  waterQuad.setModelBound(new BoundingBox());
                  waterQuad.updateModelBound();

                
                FloatBuffer normBuf = waterQuad.getNormalBuffer();
                normBuf.clear();
                normBuf.put(0).put(1).put(0);
                normBuf.put(0).put(1).put(0);
                normBuf.put(0).put(1).put(0);
                normBuf.put(0).put(1).put(0);

                waterEffectRenderPass.setWaterEffectOnSpatial(waterQuad);
                rootNode.attachChild(waterQuad);

                waterEffectRenderPass.setReflectedScene(skybox);
                waterEffectRenderPass.addReflectedScene(reflectionTerrain);
                waterEffectRenderPass.setSkybox(skybox);
                pManager.add(waterEffectRenderPass);

                RenderPass rootPass = new RenderPass();
                rootPass.add(rootNode);
                pManager.add(rootPass);

    }


private void buildSkyBox() {
        skybox = new Skybox("skybox", 500, 500, 500);

        String dir = "jmetest/data/skybox1/";
        Texture north = TextureManager.loadTexture(SceneManager.class
                .getClassLoader().getResource(dir + "1.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture south = TextureManager.loadTexture(SceneManager.class
                .getClassLoader().getResource(dir + "3.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture east = TextureManager.loadTexture(SceneManager.class
                .getClassLoader().getResource(dir + "2.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture west = TextureManager.loadTexture(SceneManager.class
                .getClassLoader().getResource(dir + "4.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture up = TextureManager.loadTexture(SceneManager.class
                .getClassLoader().getResource(dir + "6.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);
        Texture down = TextureManager.loadTexture(SceneManager.class
                .getClassLoader().getResource(dir + "5.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap,
                Texture.MagnificationFilter.Bilinear);

        skybox.setTexture(Skybox.Face.North, north);
        skybox.setTexture(Skybox.Face.West, west);
        skybox.setTexture(Skybox.Face.South, south);
        skybox.setTexture(Skybox.Face.East, east);
        skybox.setTexture(Skybox.Face.Up, up);
        skybox.setTexture(Skybox.Face.Down, down);
        skybox.preloadTextures();

        CullState cullState = MatraSystem.disp.getRenderer().createCullState();
        cullState.setCullFace(CullState.Face.None);
        cullState.setEnabled(true);
        skybox.setRenderState(cullState);

        ZBufferState zState = MatraSystem.disp.getRenderer().createZBufferState();
        zState.setEnabled(false);
        skybox.setRenderState(zState);

        FogState fs = MatraSystem.disp.getRenderer().createFogState();
        fs.setEnabled(false);
        skybox.setRenderState(fs);

        skybox.setLightCombineMode(Spatial.LightCombineMode.Off);
        skybox.setCullHint(Spatial.CullHint.Never);
        skybox.setTextureCombineMode(Spatial.TextureCombineMode.Replace);
        skybox.updateRenderState();

        skybox.lockBounds();
        skybox.lockMeshes();
    }

    private void setVertexCoords(float x, float y, float z) {
           FloatBuffer vertBuf = waterQuad.getVertexBuffer();
           vertBuf.clear();

           vertBuf.put(x - farPlane).put(y).put(z - farPlane);
           vertBuf.put(x - farPlane).put(y).put(z + farPlane);
           vertBuf.put(x + farPlane).put(y).put(z + farPlane);
           vertBuf.put(x + farPlane).put(y).put(z - farPlane);
       }

       private void setTextureCoords(int buffer, float x, float y,
               float textureScale) {
           x *= textureScale * 0.5f;
           y *= textureScale * 0.5f;
           textureScale = farPlane * textureScale;
           FloatBuffer texBuf;
           texBuf = waterQuad.getTextureCoords(buffer).coords;
           texBuf.clear();
           texBuf.put(x).put(textureScale + y);
           texBuf.put(x).put(y);
           texBuf.put(textureScale + x).put(y);
           texBuf.put(textureScale + x).put(textureScale + y);
       }


}
